/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frmem_stat.c                                       */
/*  NOTE      =                                                    */
/*  DATE      = 2015/01/08 by yaohl                                */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#include "frcomm.h"
#include "frmem.h"
#include "frmem_stat.h"

#if FR_MEM_STAT

    //内存管理
    //4byte     4byte   data
    //4byte:Frmemstat_mng位置
    //4byte:内存空间大小
    //data:实际使用的数据

    //数据块的头部，保留空间大小(用于保留统计信息)
    #define FR_MEMSTAT_RESERVE (sizeof(unsigned int)*2)

    typedef struct
    {
        unsigned int ui_idx;
        char arr_name[30];

        unsigned long ul_mem_used;
    } Frmemstat;

    #define FR_MEMSTAT_COUNT_MAX    500
    typedef struct
    {
        int i_count; //当前使用的个数
        int i_max;   //最大多少个
        Frmemstat *p_memstat[FR_MEMSTAT_COUNT_MAX];
    } Frmemstat_mng;

    /* 该结构体所有模块(so)都能访问 */
    Frmemstat_mng g_st_memstat_mng={0,FR_MEMSTAT_COUNT_MAX};
    pthread_rwlock_t  rwlock_memstat = PTHREAD_RWLOCK_INITIALIZER;

    /* 使用 static后，每个动态链接库看到不同的Frmemstat
     * 由此实现不通模块使用不同的内存管理模块 */
    static Frmemstat *g_p_st_memstat = NULL;

    /*******************************************************************************
    *  FUNC     :  缓存池初始化
    *  ARGS     :
    *  RTN      :  FR_SUCC (success)
    *           :  FR_FAIL (failed)
    *  NOTE     :
    *******************************************************************************/
    int  __fr_memstat_init(size_t s_size, const char *p_slab_name)
    {
        int i_ret, i_loop, i_idx=-1;

        pthread_rwlock_wrlock(&rwlock_memstat);
        if(g_p_st_memstat)
        {
            frdbg("already init\n");
            pthread_rwlock_unlock(&rwlock_memstat);
            return FR_SUCC;
        }

        i_ret = __frcomm_slab_init(s_size, p_slab_name);
        if(i_ret == FR_FAIL)
        {
            pthread_rwlock_unlock(&rwlock_memstat);
            return FR_FAIL;
        }

        //没有节点时，所有节点都清空
        if(g_st_memstat_mng.i_count == 0)
        {
            for(i_loop=0; i_loop < g_st_memstat_mng.i_max; i_loop++ )
                g_st_memstat_mng.p_memstat[i_loop] = NULL;
        }

        //获取管理用内存
        g_p_st_memstat = malloc(sizeof(Frmemstat));
        if(g_p_st_memstat == NULL)
        {
            frwarn("malloc err\n");
            goto ERROR;
        }

        snprintf(g_p_st_memstat->arr_name, sizeof(g_p_st_memstat->arr_name), "%s", p_slab_name);
        g_p_st_memstat->ul_mem_used =0L;

        if(g_st_memstat_mng.i_count >= g_st_memstat_mng.i_max)
        {
            frwarn("g_st_memstat_mng.i_count >= g_st_memstat_mng.i_max\n");
            goto ERROR;
        }

        //查询空节点
        i_idx=-1;
        for(i_loop=0; i_loop < g_st_memstat_mng.i_max; i_loop++)
        {
            if(g_st_memstat_mng.p_memstat[i_loop] == NULL)
            {
                i_idx = i_loop;
                break;
            }
        }

        if(i_idx < 0)
        {
            frwarn("no space in memstat_mng\n");
            goto ERROR;
        }

        g_p_st_memstat->ui_idx = i_idx;
        g_st_memstat_mng.p_memstat[i_idx] = g_p_st_memstat;
        g_st_memstat_mng.i_count++;

        pthread_rwlock_unlock(&rwlock_memstat);
        return FR_SUCC;

    ERROR:
        if(g_p_st_memstat)
            free(g_p_st_memstat);
        g_p_st_memstat = NULL;
        pthread_rwlock_unlock(&rwlock_memstat);
        __frcomm_slab_destroy();
        return FR_FAIL;
    }

    /*******************************************************************************
    *  FUNC     :  内存分配函数
    *  ARGS     :  s_size   (内存空间大小)
    *  RTN      :  成功返回内存地址，出错返回NULL
    *  NOTE     :
    *******************************************************************************/
    void *__fr_memstat_malloc(size_t s_size)
    {
        void *p_data=NULL;

        if(s_size <=0)
            return NULL;

        pthread_rwlock_wrlock(&rwlock_memstat);
        if(g_p_st_memstat == NULL)
        {
            pthread_rwlock_unlock(&rwlock_memstat);
            return NULL;
        }

        p_data = __frcomm_malloc(s_size + FR_MEMSTAT_RESERVE);
        if(p_data == NULL)
        {
            pthread_rwlock_unlock(&rwlock_memstat);
            return NULL;
        }

        *(unsigned int *)p_data = g_p_st_memstat->ui_idx;
        *(unsigned int *)(p_data+sizeof(unsigned int)) = s_size + FR_MEMSTAT_RESERVE;
        g_p_st_memstat->ul_mem_used += s_size + FR_MEMSTAT_RESERVE;
        pthread_rwlock_unlock(&rwlock_memstat);

        return (p_data+FR_MEMSTAT_RESERVE);
    }

    /*******************************************************************************
    *  FUNC     :  内存数据拷贝，并重新生成内存空间
    *  ARGS     :  p_src    (拷贝数据串地址)
                :  s_size   (拷贝数据大小)
    *  RTN      :  成功返回内存地址，出错返回NULL
    *  NOTE     :
    *******************************************************************************/
    void *__fr_memstat_memdup(const char *p_src, size_t s_size)
    {
        void *p_data=NULL;

        if(s_size <=0)
            return NULL;

        p_data = __fr_memstat_malloc(s_size);
        if(p_data == NULL)
            return NULL;

        memcpy(p_data, p_src, s_size);
        return p_data;
    }
    /*******************************************************************************
    *  FUNC     :  字符串拷贝，并重新生成内存空间(功能同strdup)
    *  ARGS     :  p_src    (拷贝字符串地址)
    *  RTN      :  成功返回内存地址，出错返回NULL
    *  NOTE     :
    *******************************************************************************/
    char *__fr_memstat_strdup(const char *p_src)
    {
        void *p_data=NULL;
        size_t s_size;

        if(p_src == NULL)
            return NULL;

        s_size = strlen(p_src) + 1;
        p_data = __fr_memstat_malloc(s_size);
        if(p_data == NULL)
            return NULL;

        memcpy(p_data, p_src, s_size);
        return p_data;
    }

    /*******************************************************************************
    *  FUNC     :  内存释放函数(功能同free)
    *  ARGS     :  p_free_data (释放地址)
    *  RTN      :
    *  NOTE     :
    *******************************************************************************/
    void __fr_memstat_free(void *p_free_data)
    {
        unsigned int ui_size=-1, ui_idx=0;
        Frmemstat *p_st_memstat=NULL;

        if (p_free_data == NULL)
            return;

        ui_idx  = *(unsigned int *)(p_free_data - FR_MEMSTAT_RESERVE);
        ui_size = *(unsigned int *)(p_free_data - FR_MEMSTAT_RESERVE+ sizeof(unsigned int));
        __frcomm_free( (void*) (p_free_data - FR_MEMSTAT_RESERVE) );
        if(ui_idx >= g_st_memstat_mng.i_max)
            return;

        pthread_rwlock_wrlock(&rwlock_memstat);
        p_st_memstat = g_st_memstat_mng.p_memstat[ui_idx];
        if(p_st_memstat == NULL)
        {
            pthread_rwlock_unlock(&rwlock_memstat);
            return;
        }

        if(p_st_memstat->ul_mem_used > ui_size)
            p_st_memstat->ul_mem_used -= ui_size;
        pthread_rwlock_unlock(&rwlock_memstat);
        return;
    }

    /*******************************************************************************
    *  FUNC     :  释放当前缓存池
    *  ARGS     :
    *  RTN      :
    *  NOTE     :
    *******************************************************************************/
    void __fr_memstat_destroy(void)
    {
        pthread_rwlock_wrlock(&rwlock_memstat);
        if(g_p_st_memstat == NULL)
        {
            pthread_rwlock_unlock(&rwlock_memstat);
            return;
        }

        g_st_memstat_mng.i_count--;
        g_st_memstat_mng.p_memstat[g_p_st_memstat->ui_idx] = NULL;
        free(g_p_st_memstat);
        g_p_st_memstat = NULL;
        __frcomm_slab_destroy();

        pthread_rwlock_unlock(&rwlock_memstat);
        return;
    }

    /*******************************************************************************
    *  FUNC     :  获取当前使用内存信息
    *  ARGS     :
    *  RTN      :
    *  NOTE     :
    *******************************************************************************/
    void __fr_memstat_info(char **pp_outbuff)
    {
        char *p_buff=NULL;
        int i_buff_size=256;

        pthread_rwlock_rdlock(&rwlock_memstat);
        if(g_p_st_memstat == NULL)
            goto END;

        p_buff = __frcomm_malloc(i_buff_size);
        if(p_buff == NULL)
            goto END;

        snprintf(p_buff, i_buff_size, "\tname:%s\tused:%lu(%.2fM)\n"
                , g_p_st_memstat->arr_name
                , g_p_st_memstat->ul_mem_used
                , g_p_st_memstat->ul_mem_used/1024.0/1024.0);
        if(pp_outbuff == NULL)
        {
            printf("memory info one\n%s\n", p_buff);
            __frcomm_free(p_buff);
        }
        else
            *pp_outbuff = p_buff;

        pthread_rwlock_unlock(&rwlock_memstat);
        return;

    END:
        pthread_rwlock_unlock(&rwlock_memstat);
        return;
    }

    /*******************************************************************************
    *  FUNC     :  获取当前所有使用内存信息
    *  ARGS     :
    *  RTN      :
    *  NOTE     :
    *******************************************************************************/
    void __fr_memstat_info_all(char **pp_outbuff)
    {
        char *p_buff=NULL, *p_other_stat=NULL;
        char *p_append_data="\n\t================\n";
        int i_loop, i_buff_size=2048, i_used=0, i_ret_fun=0;

        __frcomm_slab_stat(&p_other_stat);
        if(p_other_stat)
            i_buff_size += strlen(p_other_stat) + strlen(p_append_data) +1;

        p_buff = __fr_memstat_malloc(i_buff_size);
        if(p_buff == NULL)
        {
            if(p_other_stat)
                __frcomm_free(p_buff);
            return;
        }
        *p_buff = '\0';

        if(p_other_stat)
        {
            i_used = strlen(p_other_stat);
            memcpy(p_buff, p_other_stat, i_used+1);
            __frcomm_free(p_other_stat);
            p_other_stat = NULL;
            snprintf(p_buff+i_used, i_buff_size-i_used, "%s", p_append_data);
            i_used += strlen(p_append_data);
        }

        pthread_rwlock_rdlock(&rwlock_memstat);
        if(g_st_memstat_mng.i_count <=0 )
            goto END;

        for(i_loop=0; i_loop < g_st_memstat_mng.i_max; i_loop++)
        {
            if(g_st_memstat_mng.p_memstat[i_loop] == NULL)
                continue;
            if(i_buff_size < i_used + 3 )
                break;
            i_ret_fun = snprintf(p_buff+i_used, i_buff_size-i_used, "\tname:%s\tused:%lu(%.2fM)\n"
                                , g_st_memstat_mng.p_memstat[i_loop]->arr_name
                                , g_st_memstat_mng.p_memstat[i_loop]->ul_mem_used
                                , g_st_memstat_mng.p_memstat[i_loop]->ul_mem_used/1024.0/1024.0);
            i_used += i_ret_fun;
        }

        if(pp_outbuff == NULL)
        {
            printf("memory info\n%s\n", p_buff);
            __frcomm_free(p_buff);
        }
        else
            *pp_outbuff = p_buff;

    END:
        pthread_rwlock_unlock(&rwlock_memstat);
        return;
    }

    /*******************************************************************************
    *  FUNC     :  获取当前内存总量
    *  ARGS     :
    *  RTN      :
    *  NOTE     :  使用内存量(byte)
    *******************************************************************************/
    unsigned int __fr_memstat_all_used(void)
    {
        int i_loop=0;
        unsigned int ui_all_used=0;

        pthread_rwlock_rdlock(&rwlock_memstat);
        if(g_st_memstat_mng.i_count <=0 )
            goto END;

        for(i_loop=0; i_loop < g_st_memstat_mng.i_max; i_loop++)
        {
            if(g_st_memstat_mng.p_memstat[i_loop] == NULL)
                continue;

            ui_all_used += g_st_memstat_mng.p_memstat[i_loop]->ul_mem_used;
        }

    END:
        pthread_rwlock_unlock(&rwlock_memstat);
        return ui_all_used;
    }
#endif
